package com.java2nb.novel.pay.service.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.java2nb.novel.pay.common.SignUtils;
import com.java2nb.novel.pay.dto.QueryPayOrderRequestDTO;
import com.java2nb.novel.pay.entity.MchAppConfig;
import com.java2nb.novel.pay.entity.PayOrder;
import com.java2nb.novel.pay.mapper.MchAppConfigDynamicSqlSupport;
import com.java2nb.novel.pay.mapper.MchAppConfigMapper;
import com.java2nb.novel.pay.mapper.PayOrderDynamicSqlSupport;
import com.java2nb.novel.pay.mapper.PayOrderMapper;
import com.java2nb.novel.pay.service.PayOrderQueryService;
import com.java2nb.novel.pay.vo.QueryPayOrderResponseVO;
import com.java2nb.novel.utils.OkHttpUtils;
import com.java2nb.novel.utils.OrderStatusEnum;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.mybatis.dynamic.sql.render.RenderingStrategies;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;

import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;

import static org.mybatis.dynamic.sql.SqlBuilder.isEqualTo;
import static org.mybatis.dynamic.sql.select.SelectDSL.select;

@Service
@Slf4j
public class PayOrderQueryServiceImpl implements PayOrderQueryService {
    private static final String PAY_ORDER_CACHE_KEY_PREFIX = "pay:cache:pay_order:"; // 支付订单缓存Key
    private static final long PAY_ORDER_CACHE_EXPIRE = 30; // 缓存30分钟

    @Autowired
    private PayOrderMapper payOrderMapper;
    @Autowired
    private MchAppConfigMapper mchAppConfigMapper;
    @Autowired
    private StringRedisTemplate redisTemplate;
    @Autowired
    private OkHttpUtils okHttpUtils;
    @Value("${pay.gateway.url.query}") // 支付网关查询URL：https://payapi.mqiepay.com/api/pay/query
    private String payGatewayQueryUrl;

    public QueryPayOrderResponseVO queryPayOrder(QueryPayOrderRequestDTO requestDTO) {
        QueryPayOrderResponseVO response = new QueryPayOrderResponseVO();
        try {
            // 1. 校验商户配置并获取私钥
            MchAppConfig mchAppConfig = getMchAppConfig(requestDTO.getMchNo(), requestDTO.getAppId());
            if (mchAppConfig == null || mchAppConfig.getMchStatus() != 1 || mchAppConfig.getAppStatus() != 1) {
                response.setCode("9999");
                response.setMsg("商户/应用配置异常");
                assert mchAppConfig != null;
                return signResponse(response, mchAppConfig.getSecretKey());
            }

            // 2. 验证请求签名
            Map<String, Object> requestMap = JSONObject.parseObject(JSON.toJSONString(requestDTO), Map.class);
            if (!SignUtils.verifySign(requestMap, mchAppConfig.getSecretKey(), requestDTO.getSign())) {
                response.setCode("9999");
                response.setMsg("签名验证失败");
                return signResponse(response, mchAppConfig.getSecretKey());
            }

            // 3. 先查缓存，缓存未命中查DB，DB未命中查支付网关
            QueryPayOrderResponseVO.QueryPayOrderData data = null;
            String cacheKey = getPayOrderCacheKey(requestDTO);
            String cacheData = redisTemplate.opsForValue().get(cacheKey);

            if (cacheData != null) {
                // 缓存命中
                data = JSONObject.parseObject(cacheData, QueryPayOrderResponseVO.QueryPayOrderData.class);
            } else {
                // 缓存未命中，查DB
                PayOrder payOrder = getPayOrderFromDB(requestDTO);
                if (payOrder != null) {
                    // DB命中，转换为响应数据并缓存
                    data = new QueryPayOrderResponseVO.QueryPayOrderData();
                    BeanUtils.copyProperties(payOrder,data);

                    redisTemplate.opsForValue().set(cacheKey, JSON.toJSONString(payOrder), PAY_ORDER_CACHE_EXPIRE, TimeUnit.MINUTES);
                } else {
                    // DB未命中，调用支付网关查询
                    data = queryPayOrderFromGateway(requestDTO, mchAppConfig.getSecretKey());
                    if (data .getMchOrderNo() ==null || StringUtils.isEmpty(data .getMchOrderNo())) {
                        // 网关查询结果缓存
                        redisTemplate.opsForValue().set(cacheKey, JSON.toJSONString(data), PAY_ORDER_CACHE_EXPIRE, TimeUnit.MINUTES);
                    } else {
                        response.setCode("9999");
                        response.setMsg("订单不存在");
                        return signResponse(response, mchAppConfig.getSecretKey());
                    }
                }
            }

            // 4. 组装响应
            response.setData(data);
        } catch (Exception e) {
            log.error("查询支付订单失败", e);
            response.setCode("9999");
            response.setMsg("查询失败：" + e.getMessage());
        }
        // 5. 生成响应签名
        MchAppConfig mchAppConfig = getMchAppConfig(requestDTO.getMchNo(), requestDTO.getAppId());
        return signResponse(response, mchAppConfig.getSecretKey());
    }

    // 从DB查询支付订单
    private PayOrder getPayOrderFromDB(QueryPayOrderRequestDTO requestDTO) {
        return payOrderMapper.selectOne(select(PayOrderDynamicSqlSupport.payOrderNo, PayOrderDynamicSqlSupport.mchNo, PayOrderDynamicSqlSupport.mchOrderNo,
                PayOrderDynamicSqlSupport.appId, PayOrderDynamicSqlSupport.orderState)
                .from(PayOrderDynamicSqlSupport.payOrder)
                .where(PayOrderDynamicSqlSupport.payOrderNo, isEqualTo(requestDTO.getPayOrderId()))
                .build()
                .render(RenderingStrategies.MYBATIS3));
    }

    // 调用支付网关查询订单
    private QueryPayOrderResponseVO.QueryPayOrderData queryPayOrderFromGateway(QueryPayOrderRequestDTO requestDTO, String secretKey) throws IOException, IOException {
        // 构建网关请求参数（含签名）
        Map<String, Object> gatewayParams = new HashMap<>();
        gatewayParams.put("mchNo", requestDTO.getMchNo());
        gatewayParams.put("appId", requestDTO.getAppId());
        gatewayParams.put("payOrderId", requestDTO.getPayOrderId()); //支付订单号
        gatewayParams.put("mchOrderNo", requestDTO.getMchOrderNo()); //商户订单号
        gatewayParams.put("reqTime", requestDTO.getReqTime());
        gatewayParams.put("version", requestDTO.getVersion());
        gatewayParams.put("signType", requestDTO.getSignType());

        // 生成签名
        String sign = SignUtils.generateSign(gatewayParams, secretKey);
        gatewayParams.put("sign", sign);

        // 调用网关
        String gatewayResponseStr = okHttpUtils.postJson(payGatewayQueryUrl, JSON.toJSONString(gatewayParams));
        JSONObject gatewayResponse = JSONObject.parseObject(gatewayResponseStr);

        // 验证网关响应签名
        if (!"0".equals(gatewayResponse.getString("code"))) {
            throw new RuntimeException("网关查询失败：" + gatewayResponse.getString("msg"));
        }
        Map<String, Object> gatewayRespMap = SignUtils.jsonToMap(gatewayResponse);
        if (!SignUtils.verifySign(gatewayRespMap, secretKey, gatewayResponse.getString("sign"))) {
            throw new RuntimeException("网关响应签名验证失败");
        }

        // 转换为响应数据
        JSONObject gatewayData = gatewayResponse.getJSONObject("data");
        QueryPayOrderResponseVO.QueryPayOrderData data = new QueryPayOrderResponseVO.QueryPayOrderData();
        BeanUtils.copyProperties(gatewayData, data);
        // 补充状态描述
        Integer payStatus = gatewayData.getInteger("payStatus");
        data.setPayStatusDesc(OrderStatusEnum.values()[payStatus].getDesc());
        return data;
    }

    // 生成支付订单缓存Key
    private String getPayOrderCacheKey(QueryPayOrderRequestDTO requestDTO) {
        if (requestDTO.getPayOrderId() != null && !requestDTO.getPayOrderId().isEmpty()) {
            return PAY_ORDER_CACHE_KEY_PREFIX + "pay:" + requestDTO.getPayOrderId();
        } else {
            return PAY_ORDER_CACHE_KEY_PREFIX + "mch:" + requestDTO.getMchNo() + ":" + requestDTO.getMchOrderNo();
        }
    }

    // 响应签名
    private QueryPayOrderResponseVO signResponse(QueryPayOrderResponseVO response, String secretKey) {
        Map<String, Object> respMap = new HashMap<>();
        respMap.put("code", response.getCode());
        respMap.put("msg", response.getMsg());
        respMap.put("data", response.getData());
        respMap.put("signType", response.getSignType());
        response.setSign(SignUtils.generateSign(respMap, secretKey));
        return response;
    }

    // 复用：获取商户配置（缓存优先）
    private MchAppConfig getMchAppConfig(String mchNo, String appId) {
        String cacheKey = "pay:mch:config:" + mchNo + ":" + appId;
        String configJson = redisTemplate.opsForValue().get(cacheKey);
        if (configJson != null) {
            return JSONObject.parseObject(configJson, MchAppConfig.class);
        }
        MchAppConfig config = mchAppConfigMapper.selectOne(
                select(MchAppConfigDynamicSqlSupport.mchNo, PayOrderDynamicSqlSupport.mchNo, MchAppConfigDynamicSqlSupport.mchNo,
                        MchAppConfigDynamicSqlSupport.appId)
                        .from(MchAppConfigDynamicSqlSupport.mchAppConfig)
                        .where(MchAppConfigDynamicSqlSupport.mchNo, isEqualTo(mchNo))
                        .and(MchAppConfigDynamicSqlSupport.appId, isEqualTo(appId))
                        .build()
                        .render(RenderingStrategies.MYBATIS3)
        );
        if (config != null) {
            redisTemplate.opsForValue().set(cacheKey, JSON.toJSONString(config), 1, TimeUnit.HOURS);
        }
        return config;
    }
}
